#include <vector>
#include <iostream>
#include <pthread.h>
#include <cstdio>
#include "Sem.h"

const int g_capacity=5;
template<class T>
class circulqueue
{
public:
    circulqueue(size_t capacity=g_capacity)
    :_qp(capacity)//初始化大小
    ,_capacity(capacity)
    ,c_step(0)
    ,p_step(0)
    ,space_sem_(capacity)
    ,data_sem_(0)
    {
      pthread_mutex_init(&clock, nullptr);
      pthread_mutex_init(&plock, nullptr);
    }

    // 多生产多消费的意义在哪里？？你不要狭隘的认为，把任务或者数据放在交易场所，就是生产和消费啦
// 将数据或者任务生产前和拿到之后处理，才是最耗费时间的。
// 生产的本质：私有的任务-> 公共空间中
// 消费的本质：公共空间中的任务-> 私有的

// 信号量本质是一把计数器-> 计数器的意义是什么？？可以不用进入临界区，就可以得知资源情况，甚至可以减少临界区内部的判断！
// 申请锁 -> 判断与访问 -> 释放锁 --> 本质是我们并不清楚临界资源的情况！！
// 信号量要提前预设资源的情况，而且在pv变化过程中，我们可以在外部就能知晓临界资源的情况！
    void Push(const T& in)
    {
      // 先申请信号量(0)
        space_sem_.p();
        pthread_mutex_lock(&plock); // ?
        // 一定是竞争成功的生产者线程 -- 就一个！
        _qp[p_step++] = in;
        p_step %= _capacity;
        pthread_mutex_unlock(&plock);
        data_sem_.v();
    }

    void Pop(T* out)
    {
      data_sem_.p();
        pthread_mutex_lock(&clock);
        // 一定是竞争成功的消费者线程 -- 就一个！
        *out = _qp[c_step++];
        c_step %= _capacity;
        pthread_mutex_unlock(&clock);
        space_sem_.v();
    }

    ~circulqueue()
    {
      pthread_mutex_destroy(&clock);
      pthread_mutex_destroy(&plock);
    }
private:
    std::vector<T> _qp;//容器
    size_t _capacity;//体积
    int c_step;//消费
    int p_step;//生产
    Sem space_sem_;//生产空间
    Sem data_sem_;//消费空间
    pthread_mutex_t clock;//消费锁
    pthread_mutex_t plock;//生产锁
};